package com.zoespeer.food_delivery_comment_api.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.zoespeer.food_delivery_comment_api.common.JwtUtil;
import com.zoespeer.food_delivery_comment_api.common.exception.UserException;
import com.zoespeer.food_delivery_comment_api.common.exception.VerifyCodeException;
import com.zoespeer.food_delivery_comment_api.entity.Review;
import com.zoespeer.food_delivery_comment_api.entity.User;
import com.zoespeer.food_delivery_comment_api.entity.UserFavorites;
import com.zoespeer.food_delivery_comment_api.entity.Restaurant;
import com.zoespeer.food_delivery_comment_api.mapper.FavoriteMapper;
import com.zoespeer.food_delivery_comment_api.mapper.ReviewMapper;
import com.zoespeer.food_delivery_comment_api.mapper.UserMapper;
import com.zoespeer.food_delivery_comment_api.mapper.RestaurantMapper;
import com.zoespeer.food_delivery_comment_api.service.UserService;
import com.zoespeer.food_delivery_comment_api.vo.*;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Date;
import java.util.Random;
import java.util.concurrent.TimeUnit;
// (必须添加) 在 UserServiceImpl 顶部 import
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import java.security.Key;


@Service
public class UserServiceImpl implements UserService {
    private final UserMapper userMapper;
    private final BCryptPasswordEncoder passwordEncoder;
    private final RedisTemplate<String, Object> redisTemplate;
    private final FavoriteMapper userFavoritesMapper;
    private final ReviewMapper reviewMapper;
    private final JdbcTemplate jdbcTemplate;
    private final RestaurantMapper restaurantMapper;
//    private final String JWT_SECRET_KEY = "your_jwt_secret_key"; // 替换为实际JWT密钥
//
//    // Token黑名单前缀（用于Redis存储）
//    private static final String TOKEN_BLACKLIST_PREFIX = "token:blacklist:";
    // (必须添加) 类的成员变量
// (修改点) 在这里添加缺失的常量定义
private static final String TOKEN_BLACKLIST_PREFIX = "token:blacklist:";
    private static final String JWT_SECRET_KEY = "waimai-comment-api-secret-key-2025";
    private static final Key key = Keys.hmacShaKeyFor(JWT_SECRET_KEY.getBytes());
    @Autowired
    public UserServiceImpl(UserMapper userMapper,
                           BCryptPasswordEncoder passwordEncoder,
                           RedisTemplate<String, Object> redisTemplate,
                           FavoriteMapper userFavoritesMapper,
                           ReviewMapper reviewMapper,
                           JdbcTemplate jdbcTemplate,
                           RestaurantMapper restaurantMapper) {
        this.userMapper = userMapper;
        this.passwordEncoder = passwordEncoder;
        this.redisTemplate = redisTemplate;
        this.userFavoritesMapper = userFavoritesMapper;
        this.reviewMapper = reviewMapper;
        this.jdbcTemplate = jdbcTemplate;
        this.restaurantMapper = restaurantMapper;
    }

    @Override
    public UserVO login(LoginVO loginVO) {
        User user = userMapper.selectByEmail(loginVO.getEmail());
        if (user == null) {
            throw new UserException("用户不存在");
        }

        if (!passwordEncoder.matches(loginVO.getPassword(), user.getPassword())) {
            throw new UserException("密码错误");
        }

        String token = JwtUtil.generateToken(user.getUserId());

        UserVO userVO = new UserVO();
        userVO.setUserId(user.getUserId().toString());
        userVO.setNickname(user.getNickname());
        userVO.setToken(token);
        userVO.setRole(0);
        return userVO;
    }

    @Override
    public void register(RegisterVO registerVO) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getEmail, registerVO.getEmail());
        User existingUser = userMapper.selectOne(queryWrapper);
        if (existingUser != null) {
            // 邮箱已存在时，不执行注册，由 Controller 转发到忘记密码逻辑
            throw new UserException("该邮箱已被注册，请走忘记密码流程");
        }

        // 校验用户名（注册时必填）
        if (registerVO.getUsername() == null || registerVO.getUsername().length() < 2 || registerVO.getUsername().length() > 20) {
            throw new UserException("用户名长度需为 2-20 位");
        }

        // 原验证码、密码加密逻辑保持不变
        String checkCode = registerVO.getCheckCode();
        if (checkCode == null || checkCode.length() != 4) {
            throw new VerifyCodeException("验证码格式错误");
        }
        String cachedCode = (String) redisTemplate.opsForValue().get("verify_code:" + registerVO.getEmail());
        if (cachedCode == null || !cachedCode.equals(checkCode)) {
            throw new VerifyCodeException("验证码错误或已过期");
        }

        String encryptedPassword = passwordEncoder.encode(registerVO.getPassword());
        User newUser = new User();
        newUser.setEmail(registerVO.getEmail());
        newUser.setNickname(registerVO.getUsername()); // 用户名作为昵称
        newUser.setPassword(encryptedPassword);
        newUser.setStatus("active");

        userMapper.insert(newUser);
        redisTemplate.delete("verify_code:" + registerVO.getEmail());
    }

    @Override
    public void resetPassword(RegisterVO registerVO) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getEmail, registerVO.getEmail());
        User existingUser = userMapper.selectOne(queryWrapper);
        if (existingUser == null) {
            // 邮箱不存在时，不执行重置，由 Controller 转发到注册逻辑
            throw new UserException("该邮箱未注册，请走注册流程");
        }

        // 2. 新增：判断昵称是否有值，有则报错（提醒注册过不能在此改昵称）
        String username = registerVO.getUsername();
        if (username != null && !username.trim().isEmpty()) {
            throw new UserException("该邮箱已注册，无法通过重置密码修改昵称，请通过「个人中心」修改");
        }
        // 验证码校验（和注册逻辑一致）
        String checkCode = registerVO.getCheckCode();
        if (checkCode == null || checkCode.length() != 4) {
            throw new VerifyCodeException("验证码格式错误");
        }
        String cachedCode = (String) redisTemplate.opsForValue().get("verify_code:" + registerVO.getEmail());
        if (cachedCode == null || !cachedCode.equals(checkCode)) {
            throw new VerifyCodeException("验证码错误或已过期");
        }

        // 密码加密并更新
        String encryptedPassword = passwordEncoder.encode(registerVO.getPassword());
        existingUser.setPassword(encryptedPassword);
        userMapper.updateById(existingUser);

        redisTemplate.delete("verify_code:" + registerVO.getEmail());
    }


    @Override
    public UserInfoVO getUserInfo(Integer userId) {
        User user = userMapper.selectByUserId(userId);
        if (user == null) {
            throw new UserException("用户不存在");
        }

        UserInfoVO userInfoVO = new UserInfoVO();
        userInfoVO.setUsername(user.getNickname());
        userInfoVO.setAvatar(user.getAvatarUrl());
        userInfoVO.setEmail(user.getEmail());
        return userInfoVO;
    }

    private static final long CODE_EXPIRE_MINUTES = 5;
    @Override
    public void sendCheckCode(SendCheckCodeVO sendCheckCodeVO) {
        String email = sendCheckCodeVO.getEmail();

        String checkCode = generateCheckCode();
        redisTemplate.opsForValue()
                .set("verify_code:" + email, checkCode, CODE_EXPIRE_MINUTES, TimeUnit.MINUTES);
    }

    private String generateCheckCode() {
        Random random = new Random();
        int codeNum = random.nextInt(9000) + 1000;
        return String.valueOf(codeNum);
    }

    @Override
    public User changeMessage(Integer userId, UpdateUserInfoVO request) {
        User user = userMapper.selectById(userId);
        if (user == null) {
            throw new UserException("用户不存在");
        }

        LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(User::getUserId, userId);

        if (request.getAvatar_url() != null && !request.getAvatar_url().trim().isEmpty()) {
            updateWrapper.set(User::getAvatarUrl, request.getAvatar_url().trim());
        }

        if (request.getNickname() != null && !request.getNickname().trim().isEmpty()) {
            updateWrapper.set(User::getNickname, request.getNickname().trim());
        }

        if (updateWrapper.isEmptyOfWhere()) {
            return user;
        }

        updateWrapper.set(User::getUpdatedAt, LocalDateTime.now());

        int rows = userMapper.update(null, updateWrapper);
        if (rows <= 0) {
            throw new UserException("修改个人信息失败，请重试");
        }

        return userMapper.selectById(userId);
    }

    @Transactional
    @Override
    public void deleteMyself(DeleteUserVO request) {
        // 1. 接收String类型userId并转换为Integer（适配Entity层）
        String userIdStr = request.getUserId(); // 从VO获取String类型userId
        Integer userId;
        try {
            userId = Integer.parseInt(userIdStr);
        } catch (NumberFormatException e) {
            throw new UserException("用户ID格式错误，需为数字");
        }

        // 2. 查询用户是否存在
        User user = userMapper.selectById(userId);
        if (user == null) {
            throw new UserException("用户不存在，无需注销");
        }

        // 3. 更新餐厅表（applicant_id为Integer类型，直接用userId）
        LambdaUpdateWrapper<Restaurant> restaurantUpdateWrapper = new LambdaUpdateWrapper<>();
        restaurantUpdateWrapper.eq(Restaurant::getApplicantId, userId)
                .set(Restaurant::getApplicantId, null);
        restaurantMapper.update(null, restaurantUpdateWrapper);

        // 4. 删除点赞记录（SQL参数用String或Integer均可，此处保持String）
        String deleteLikeSql = "DELETE FROM review_likes WHERE user_id = ?";
        jdbcTemplate.update(deleteLikeSql, userIdStr); // 或用userId（数据库兼容）

        // 5. 删除评论（QueryWrapper中用Integer类型userId，避免类型转换问题）
        QueryWrapper<Review> reviewWrapper = new QueryWrapper<>();
        reviewWrapper.eq("user_id", userId); // 改用Integer类型userId
        reviewMapper.delete(reviewWrapper);

        // 6. 删除收藏（同理用Integer类型userId）
        QueryWrapper<UserFavorites> favoritesWrapper = new QueryWrapper<>();
        favoritesWrapper.eq("user_id", userId); // 改用Integer类型userId
        userFavoritesMapper.delete(favoritesWrapper);

        // 7. 删除用户（用Integer类型userId）
        int deleteUser = userMapper.deleteById(userId);
        if (deleteUser <= 0) {
            throw new UserException("注销账号失败，请重试");
        }
    }

    @Override
    public void changePassword(ChangePasswordVO changePasswordVO) {
        Integer userId;
        try {
            userId = Integer.parseInt(changePasswordVO.getUserId());
        } catch (NumberFormatException e) {
            throw new UserException("用户ID格式错误");
        }

        User user = userMapper.selectById(userId);
        if (user == null) {
            throw new UserException("用户不存在");
        }

        if (!passwordEncoder.matches(changePasswordVO.getOldPwd(), user.getPassword())) {
            throw new UserException("原密码错误");
        }

        String newEncryptedPwd = passwordEncoder.encode(changePasswordVO.getNewPwd());
        user.setPassword(newEncryptedPwd);
        userMapper.updateById(user);
    }

    // (必须替换)
    @Override
    public void logout(String token, String userId) {
        Integer userIdInt;
        try {
            userIdInt = Integer.parseInt(userId);
        } catch (NumberFormatException e) {
            throw new UserException("用户ID格式错误");
        }

        Integer tokenUserId;
        Claims claims;
        try {
            // (修复点) 使用正确的 parserBuilder 和 key
            claims = Jwts.parserBuilder()
                    .setSigningKey(key)
                    .build()
                    .parseClaimsJws(token)
                    .getBody();
            tokenUserId = Integer.parseInt(claims.getSubject());
        } catch (Exception e) {
            throw new UserException("Token无效或已过期");
        }

        if (!tokenUserId.equals(userIdInt)) {
            throw new UserException("Token与用户ID不匹配，无权注销");
        }

        long remainingTime;
        try {
            long expirationTime = claims.getExpiration().getTime();
            remainingTime = expirationTime - System.currentTimeMillis();
        } catch (Exception e) {
            remainingTime = 0;
        }

        if (remainingTime <= 0) {
            throw new UserException("Token已过期，无需注销");
        }

        String blacklistKey = TOKEN_BLACKLIST_PREFIX + token;
        redisTemplate.opsForValue().set(blacklistKey, "invalid", remainingTime, TimeUnit.MILLISECONDS);
    }
    @Override
    public TokenValidateVO validateToken(String token) {
        TokenValidateVO result = new TokenValidateVO();
        result.setValid(false);

        if (token == null || token.trim().isEmpty()) {
            return result;
        }
        // 2. 新增：移除 Bearer 前缀（如果有）
        String pureToken = token.trim();
        if (pureToken.startsWith("Bearer ")) { // 判断是否以 "Bearer " 开头（注意空格）
            pureToken = pureToken.substring("Bearer ".length()); // 截取空格后的纯 Token
        }
        // 【修复点 1】黑名单校验：用纯 Token 生成键（和 logout 存入的键一致）
        String blacklistKey = TOKEN_BLACKLIST_PREFIX + pureToken;
        if (redisTemplate.hasKey(blacklistKey)) {
            return result;
        }

        try {
            // 解析 Token，验证签名和过期时间
            Claims claims = Jwts.parserBuilder()
                    .setSigningKey(key)
                    .build()
                    .parseClaimsJws(pureToken)
                    .getBody();

            // 解析成功且未过期，Token 有效
            result.setValid(true);
        } catch (Exception e) {
            // 解析失败（签名错误、已过期等），Token 无效
            result.setValid(false);
        }

        return result;
    }
}